package cn.yunyichina.provider.message.alipay.utils;

import cn.yunyichina.provider.SpringContextHolder;
import cn.yunyichina.provider.framework.dubbo.service.BaseService;
import cn.yunyichina.provider.framework.dubbo.service.MessageService;
import cn.yunyichina.provider.framework.dubbo.service.PayService;
import cn.yunyichina.provider.framework.exception.CallException;
import cn.yunyichina.provider.iface.entity.*;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.message.ResendRuleVo;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingResponse;
import cn.yunyichina.provider.message.alipay.AlipayMobilePublicMessageMatcherSendRequest;
import cn.yunyichina.provider.message.alipay.AlipayMobilePublicMessageMatcherSendResponse;
import cn.yunyichina.provider.message.alipay.constant.AlipayConstant;
import cn.yunyichina.provider.message.alipay.dao.MsgLogDao;
import cn.yunyichina.provider.message.alipay.entity.ImageMessage;
import cn.yunyichina.provider.message.alipay.entity.MsgTemplateContent;
import cn.yunyichina.provider.message.alipay.entity.RegNotifyRequest;
import cn.yunyichina.provider.message.alipay.entity.RegNotifyResponse;
import cn.yunyichina.provider.message.alipay.factory.AlipayAPIClientFactory;
import cn.yunyichina.provider.message.entity.RegNotify;
import cn.yunyichina.utils.commons.IDUtils;
import cn.yunyichina.utils.convert.JsonUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayMobilePublicMessageCustomSendRequest;
import com.alipay.api.request.AlipayMobilePublicMessageSingleSendRequest;
import com.alipay.api.request.AlipayOpenPublicMessageTotalSendRequest;
import com.alipay.api.response.AlipayMobilePublicMessageCustomSendResponse;
import com.alipay.api.response.AlipayMobilePublicMessageSingleSendResponse;
import com.alipay.api.response.AlipayOpenPublicMessageTotalSendResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 支付宝消息异步发送工具类
 * 
 * */
public class AlipayMessageSendUtils {

	/** 线程池 */
	private static ExecutorService executors = Executors.newCachedThreadPool();

	private static Logger logger = LoggerFactory.getLogger(AlipayMessageSendUtils.class);
	
	/**
	 * 消息重发重试间隔，单位：秒
	 */
	private static int[] resendTimeLong = {30,60,90,120,300,330,360,390,420,450};
	
	private static HospitalCodeAndAppVo getHospitalInfo(String hospitalCode) {
		JSONObject param = new JSONObject();
		param.put("hospital_code", hospitalCode);
		param.put("app_code", "alipay");
		HospitalCodeAndAppVo hospitalCodeAndAppVo = JsonUtils.parseObject(BaseService.callHumpFromInternal("yyt.base.hospital.appinfo.get", JsonUtils.toJsonString(param)).getResult(),HospitalCodeAndAppVo.class);
		logger.debug("yyt.base.hospital.appinfo.get返回："+ JsonUtils.toJsonString(hospitalCodeAndAppVo));
		return hospitalCodeAndAppVo;
	}
	
	/**
	 * 获取医院和平台的消息配置关系
	 * @param hospitalCode
	 * @return
	 */
	private static HospitalPlatformRelate getMessagePlatform(String hospitalCode) {
		JSONObject param = new JSONObject();
		param.put("hospital_code", hospitalCode);
		param.put("app_code", "alipay");
		HospitalPlatformRelate hospitalPlatformRelate = JsonUtils.parseObject(BaseService.callHumpFromInternal("yyt.base.hospital.message.platform.get", JsonUtils.toJsonString(param)).getResult(),HospitalPlatformRelate.class);
		logger.debug("yyt.base.hospital.message.platform.get返回："+ JsonUtils.toJsonString(hospitalPlatformRelate));
		return hospitalPlatformRelate;
	}
	
	public static PaymentSettingResponse getAppInfo(JSONObject jsonObj) {
		
		ResCommon<PaymentSettingResponse> responsePayment= PayService.getPayClient().queryPaymentSettingByAppcodeAndOrgcodeAndPaymode(jsonObj.getString("org_app_code"), jsonObj.getString("org_code"), (short)12);
		if ( ! "0".equals(responsePayment.getResultCode())) {
			logger.error("无法获得APPID信息");
			throw new CallException(ErrorCodeDefine.MESSAGE_COMMON,"无法获得APPID信息");
		}
		logger.debug("获取的app信息："+ JsonUtils.toJsonString(responsePayment));
		PaymentSettingResponse paymentSettingResponse = responsePayment.getResult();
		
		return paymentSettingResponse;

	}

	public static void sendTextMessage(final String openId, final String orgAppCode,final String text,short platformType,final String appId,final String privateKey,final String smsMsgContent) {
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！");
			return;
		}
		logger.debug("获取App信息:open_id="+openId);
		
//		ResCommon<PaymentSettingResponse> responsePayment= PayService.getPayClient().queryPaymentSettingByAppcodeAndOrgcodeAndPaymode(orgAppCode, orgCode, platformType);
//		if ( ! "0".equals(responsePayment.getResultCode())) {
//			logger.error("无法获得APPID信息");
//			throw new CallException(ErrorCodeDefine.MESSAGE_COMMON,"无法获得APPID信息");
//		}
//		logger.debug("获取的app信息："+JsonUtils.toJsonString(responsePayment)+",open_id="+openId);
//		PaymentSettingResponse paymentSettingResponse = responsePayment.getResult();
//		
//		final String privateKey = paymentSettingResponse.getPrivateKey();
//		final String appId = paymentSettingResponse.getPayAppId();
//		
		//TODO:需要修改这个逻辑
//		final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALocAGAyUmjls8/f687w5kcFnVYxy2lze5jlR27uPAojmD2rpewErTo1wnGO31B+vZd+0eZypqPK3lKR1Yx/I+wpxIxBobgmw10p+KgofJ1TFq+YUby4XCsAa2pLKS37WbsoHjesyXgp8AA/4xhtN8aaXOAIO4l4ZiYIAzj40rWnAgMBAAECgYB/zPLFHElTF0nfGdmIhgzcAJMGubMBevgJCol/N8GrBL5quxB5fsymCHy6Fm5rjF0NR11Ebr7YA1ugP9zxWe2D9qR76753cQfawWS4F8ZudJ63JEgjApGPjykDzJEyp66/ydfAnwAMzrag2SHcCQbgr4tmgD2OAkafJeRqiSoQYQJBAOrd4WUhP1VN/CaPLWgvynsL24w+YPrb4g6QtBNaFQFpJDPsfMMiqZOudJGjBZPR5uX+GzAOVamOPPiSwDUTfusCQQDK2wDHAkkVioSpOFLLDFPQ+2cb5Le3pnQJLGcj9lQ+iKG8VkIfDOFjbYfcA9agf17ttWcaF96Y0qtCQB44Jo01AkEAhjFSKBsP+ah+KnXiBsZPlXBX99BoTsy1Y4cQLIJqwAyX78buHfw/Ea860T9o32Wt3LkMRa/bB+7KLWiDw4+pEwJAWwUVPjZaUJ4MlFk/XPg1C4oiY7Omc3LukccoqEw41K490+HoXUJMR264DRJz1SQRlhtVHbIkIPI2Ac3/QTabGQJAa0ENFsyIrrlZFQvm1VciERrOvcGUqMlKpcRCMWyIulwcP8DOfRH3HrN/XFYN9jt3zznhsLxL9EQr8NFWHnuFwQ==";
//		final String appId = "2015102000489434";
		final MsgLogExt msgLog = new MsgLogExt(openId,appId,appId,"alipay","");
		
		msgLog.setPushContent(text);
		logger.debug("发送纯文本消息:"+ JsonUtils.toJsonString(msgLog)+",open_id="+openId);
		executors.execute(new Runnable() {
			boolean sendSuccessFlag = false;
			public void run() {
				
				try {
					String requestMsg = AlipayMessageBuildUtils.buildTextMsg(openId, text);
					msgLog.setPushContent(requestMsg);
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageCustomSendRequest request = new AlipayMobilePublicMessageCustomSendRequest();
					request.setBizContent(requestMsg);
					// 2.2 使用SDK接口类发送响应
					AlipayMobilePublicMessageCustomSendResponse response;
					
					response = alipayClient.execute(request);
					if (null != response && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
						msgLog.setPushStatusSuccess();
						if (logger.isDebugEnabled()) {
							logger.debug("MessageSendUtils类sendText方法，异步发送成功，结果为：" + response.getBody()+",open_id="+openId);
						}
						
						sendSuccessFlag = true;
					} else {
						msgLog.setPushStatusFail();
						msgLog.setErrorMsg(JsonUtils.toJsonString(response));
						logger.error("MessageSendUtils类sendText方法，异步发送失败 code=" + response.getCode() + "msg：" + response.getMsg()+",open_id="+openId);
					}
				} catch (Exception e) {
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					
					logger.error("sendTextMessage方法：回复文本消息失败");
					logger.error(ErrorCodeDefine.getStackTrace(e));
				}
				finally {
					saveMsgLog(msgLog);
					if ( ! sendSuccessFlag) {
						sendSms(smsMsgContent);
 					}
				}
			}
		});
	}
	
	
	/**
	 * 发送纯文字信息
	 * 
	 * @param openId 接收人ID
	 * @param textContent 内容
	 * @param privateKey
	 * */
	public static void sendTextMessageOld(final String openId, final String hospitalCode,final String text) {
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！");
			return;
		}
		logger.debug("获取App信息:hospitalCode="+hospitalCode);
		
//		HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
//		final String privateKey = appVo.getPrivateKey();
//		final String appId = appVo.getAppId();
//		final MsgLogExt msgLog = new MsgLogExt(openId,appVo.getHospitalId(),appId,"alipay","");
		
		//TODO:需要修改这个逻辑
		final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALocAGAyUmjls8/f687w5kcFnVYxy2lze5jlR27uPAojmD2rpewErTo1wnGO31B+vZd+0eZypqPK3lKR1Yx/I+wpxIxBobgmw10p+KgofJ1TFq+YUby4XCsAa2pLKS37WbsoHjesyXgp8AA/4xhtN8aaXOAIO4l4ZiYIAzj40rWnAgMBAAECgYB/zPLFHElTF0nfGdmIhgzcAJMGubMBevgJCol/N8GrBL5quxB5fsymCHy6Fm5rjF0NR11Ebr7YA1ugP9zxWe2D9qR76753cQfawWS4F8ZudJ63JEgjApGPjykDzJEyp66/ydfAnwAMzrag2SHcCQbgr4tmgD2OAkafJeRqiSoQYQJBAOrd4WUhP1VN/CaPLWgvynsL24w+YPrb4g6QtBNaFQFpJDPsfMMiqZOudJGjBZPR5uX+GzAOVamOPPiSwDUTfusCQQDK2wDHAkkVioSpOFLLDFPQ+2cb5Le3pnQJLGcj9lQ+iKG8VkIfDOFjbYfcA9agf17ttWcaF96Y0qtCQB44Jo01AkEAhjFSKBsP+ah+KnXiBsZPlXBX99BoTsy1Y4cQLIJqwAyX78buHfw/Ea860T9o32Wt3LkMRa/bB+7KLWiDw4+pEwJAWwUVPjZaUJ4MlFk/XPg1C4oiY7Omc3LukccoqEw41K490+HoXUJMR264DRJz1SQRlhtVHbIkIPI2Ac3/QTabGQJAa0ENFsyIrrlZFQvm1VciERrOvcGUqMlKpcRCMWyIulwcP8DOfRH3HrN/XFYN9jt3zznhsLxL9EQr8NFWHnuFwQ==";
		final String appId = "2015102000489434";
		final MsgLogExt msgLog = new MsgLogExt(openId,"",appId,"alipay","");
		
		msgLog.setPushContent(text);
		logger.debug("发送纯文本消息:"+ JsonUtils.toJsonString(msgLog));
		executors.execute(new Runnable() {
			public void run() {
				
				try {
					String requestMsg = AlipayMessageBuildUtils.buildTextMsg(openId, text);
					msgLog.setPushContent(requestMsg);
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageCustomSendRequest request = new AlipayMobilePublicMessageCustomSendRequest();
					request.setBizContent(requestMsg);
					// 2.2 使用SDK接口类发送响应
					AlipayMobilePublicMessageCustomSendResponse response;
					
					response = alipayClient.execute(request);
					if (null != response && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
						msgLog.setPushStatusSuccess();
						if (logger.isDebugEnabled()) {
							logger.debug("MessageSendUtils类sendText方法，异步发送成功，结果为：" + response.getBody()+",open_id="+openId);
						}
					} else {
						msgLog.setPushStatusFail();
						msgLog.setErrorMsg(JsonUtils.toJsonString(response));
						logger.error("MessageSendUtils类sendText方法，异步发送失败 code=" + response.getCode() + "msg：" + response.getMsg()+",open_id="+openId);
					}
				} catch (Exception e) {
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					e.printStackTrace();
					logger.error("sendTextMessage方法：回复文本消息失败"+",open_id="+openId);
				}
				finally {
					saveMsgLog(msgLog);
				}
			}
		});

	}
	
	/**
	 * 发送单图文消息
	 * 
	 * @param openId 接收人ID
	 * @param privateKey
	 * @param appId 
	 * @param ImageMessage 图文消息对象
	 * */
	public static void sendSingleImageMessage(final String openId, ImageMessage imageMessage, final String appId, final String privateKey) {
		sendSingleImageMessage(openId, imageMessage.getDesc(), imageMessage.getImageUrl(), imageMessage.getTitle(), imageMessage.getUrl(),appId,privateKey);
	}

	/**
	 * 发送单图文消息
	 * 
	 * @param openId 接收人ID
	 * @param privateKey
	 * @param appId 
	 * @param desc 备注
	 * @param imgsrc 图片地址
	 * @param title 标题
	 * @param url 点击图片后转向的url
	 * */
	public static void sendSingleImageMessage(final String openId, final String desc, 
			final String imgsrc, final String title, final String url,final String appId,final String privateKey) {
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！");
			return;
		}
//		logger.debug("获取App信息:hospitalCode="+hospitalCode+",open_id="+openId);
//		HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
//		final String privateKey = appVo.getPrivateKey();
//		final String appId = appVo.getAppId();
		final MsgLogExt msgLog = new MsgLogExt(openId,appId,appId,"alipay","");
		logger.debug("发送单图文消息:"+ JsonUtils.toJsonString(msgLog)+",open_id="+openId);
		executors.execute(new Runnable() {
			public void run() {
				try {
					String requestMsg = AlipayMessageBuildUtils.buildImageTextMsg(openId, desc, imgsrc, title, url);
					msgLog.setPushContent(requestMsg);
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageCustomSendRequest request = new AlipayMobilePublicMessageCustomSendRequest();
					request.setBizContent(requestMsg);
					// 2.2 使用SDK接口类发送响应
					AlipayMobilePublicMessageCustomSendResponse response;
				
					response = alipayClient.execute(request);
					if (null != response && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
						msgLog.setPushStatusSuccess();
						if (logger.isDebugEnabled()) {
							logger.debug("MessageSendUtils类sendSingleImageText方法，异步发送成功，结果为：" + response.getBody()+",open_id="+openId);
						}
					} else {
						msgLog.setPushStatusFail();
						msgLog.setErrorMsg(JsonUtils.toJsonString(response));
						logger.error("MessageSendUtils类sendSingleImageText方法，异步发送失败 code=" + response.getCode() + "msg：" + response.getMsg()+",open_id="+openId);
					}
				} catch (Exception e) {
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					e.printStackTrace();
					logger.error("sendSingleImageMessage方法：回复单图文消息失败"+",open_id="+openId);
				}
				finally {
					saveMsgLog(msgLog);
				}
			}
		});
	}


	/**
	 * 发送多图文信息
	 * 
	 * @param openId 接收人ID
	 * @param privateKey
	 * @param meterial
	 * @param appId
	 * */
	public static void sendMultiImageMessage(final String openId,  final String hospitalCode, final List<ImageMessage> listImageMessage) {
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！");
			return;
		}
		logger.debug("获取App信息:hospitalCode="+hospitalCode+",open_id="+openId);
		HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
		final String privateKey = appVo.getPrivateKey();
		final String appId = appVo.getAppId();
		final MsgLogExt msgLog = new MsgLogExt(openId,appVo.getHospitalId(),appId,"alipay","");
		logger.debug("发送多图文消息:"+ JsonUtils.toJsonString(msgLog)+",open_id="+openId);
		executors.execute(new Runnable() {
			public void run() {
				try {
					String requestMsg = AlipayMessageBuildUtils.buildMultiImgTextMsg(openId,listImageMessage);
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageCustomSendRequest request = new AlipayMobilePublicMessageCustomSendRequest();
					request.setBizContent(requestMsg);
					// 2.2 使用SDK接口类发送响应
					AlipayMobilePublicMessageCustomSendResponse response;
				
					response = alipayClient.execute(request);
					if (null != response && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
						msgLog.setPushStatusSuccess();
						if (logger.isDebugEnabled()) {
							
							logger.debug("MessageSendUtils类sendMultiImageText方法，异步发送成功，结果为：" + response.getBody()+",open_id="+openId);
						}
					} else {
						msgLog.setPushStatusFail();
						msgLog.setErrorMsg(JsonUtils.toJsonString(response));
						msgLog.setPushContent(requestMsg);
						logger.error("MessageSendUtils类sendMultiImageText方法，异步发送失败 code=" + response.getCode() + "msg：" + response.getMsg()+",open_id="+openId);
					}
				} catch (Exception e) {
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					logger.error("sendMultiImageMessage方法：回复多图文消息失败"+",open_id="+openId);
				}
				finally {
					saveMsgLog(msgLog);
				}
			}
		});
	}
	/**
	 * 推送模版消息-支付宝
	 * 
	 * @param openId  接收人ID
	 * @param appId
	 * @param privateKey 
	 * @param msgTemplateContents 模板消息内容
	 * @param headColor  标题栏颜色
	 * @param url 点击后转向的URL
	 * @param templateId 模板ID
	 * @return
	 */
	public static void sendTemlateMessage(final String openId,  String hospitalCode,final String templateId,final List<MsgTemplateContent> msgTemplateContents,
			final String url, final String headColor,final String smsMsgContent) {
		
		logger.info("推送模版消息，收到请求->"+openId+","+hospitalCode+","+templateId+","+JSON.toJSONString(msgTemplateContents));
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！");
			return;
		}
		logger.debug("获取App信息:hospitalCode="+hospitalCode+",open_id="+openId);
		//HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
		
		//TODO:需要修改这个逻辑
		final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALocAGAyUmjls8/f687w5kcFnVYxy2lze5jlR27uPAojmD2rpewErTo1wnGO31B+vZd+0eZypqPK3lKR1Yx/I+wpxIxBobgmw10p+KgofJ1TFq+YUby4XCsAa2pLKS37WbsoHjesyXgp8AA/4xhtN8aaXOAIO4l4ZiYIAzj40rWnAgMBAAECgYB/zPLFHElTF0nfGdmIhgzcAJMGubMBevgJCol/N8GrBL5quxB5fsymCHy6Fm5rjF0NR11Ebr7YA1ugP9zxWe2D9qR76753cQfawWS4F8ZudJ63JEgjApGPjykDzJEyp66/ydfAnwAMzrag2SHcCQbgr4tmgD2OAkafJeRqiSoQYQJBAOrd4WUhP1VN/CaPLWgvynsL24w+YPrb4g6QtBNaFQFpJDPsfMMiqZOudJGjBZPR5uX+GzAOVamOPPiSwDUTfusCQQDK2wDHAkkVioSpOFLLDFPQ+2cb5Le3pnQJLGcj9lQ+iKG8VkIfDOFjbYfcA9agf17ttWcaF96Y0qtCQB44Jo01AkEAhjFSKBsP+ah+KnXiBsZPlXBX99BoTsy1Y4cQLIJqwAyX78buHfw/Ea860T9o32Wt3LkMRa/bB+7KLWiDw4+pEwJAWwUVPjZaUJ4MlFk/XPg1C4oiY7Omc3LukccoqEw41K490+HoXUJMR264DRJz1SQRlhtVHbIkIPI2Ac3/QTabGQJAa0ENFsyIrrlZFQvm1VciERrOvcGUqMlKpcRCMWyIulwcP8DOfRH3HrN/XFYN9jt3zznhsLxL9EQr8NFWHnuFwQ==";
		final String appId = "2015102000489434";
		
		final MsgLogExt msgLog = new MsgLogExt(openId,"",appId,"alipay",templateId);
		logger.debug("发送模板消息:"+ JsonUtils.toJsonString(msgLog));
		executors.execute(new Runnable() {
			public void run() {
				boolean sendSmsFlag = false;
				try {
					//延迟8秒发
					Thread.sleep(8000);
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageSingleSendRequest request = new AlipayMobilePublicMessageSingleSendRequest();
					String requestStr = "";
					try {
						requestStr = AlipayMessageBuildUtils.buildTemplateMsg(openId, templateId, msgTemplateContents, url, headColor);
						logger.info("requestStr:" + requestStr+",open_id"+openId);
						if (logger.isDebugEnabled()) {
							logger.debug("requestStr----" + requestStr+",open_id"+openId);
						}
						msgLog.setPushContent(requestStr);
					} catch (Exception e) {
						logger.error("格式解析异常");
						throw e;
					}
					request.setBizContent(requestStr);
					JSONObject jsonObject = new JSONObject();
					
					
					//如果用户没有关注导致的失败，执行重发。尝试6次重发
					for (int i = 0;i<6;i++) {
						
						// 使用SDK，调用单发接口发送纯文本消息
						AlipayMobilePublicMessageSingleSendResponse response = alipayClient.execute(request);
						logger.info("返回："+ JsonUtils.toJsonString(response));
						if (response != null && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
							msgLog.setPushStatusSuccess();
							jsonObject.put("errcode", "0");
							jsonObject.put("errmsg", response.getMsg());
							logger.info("推送模版消息成功 " + response.getCode()+",open_id"+openId);
							if (logger.isDebugEnabled()) {
								logger.debug("推送模版消息成功 : response = " + response.getBody()+",open_id"+openId);
							}
							sendSmsFlag = false;
							//发送成功，不执行重发
							break;
							
						} else {
							
							msgLog.setPushStatusFail();
							
							msgLog.setErrorMsg(JsonUtils.toJsonString(response));
							logger.error("alipayClient.execute(request) return:"+JSON.toJSONString(response)+",open_id"+openId);
							
							//用户没有关注，执行重发。尝试6次重发
							if (response.getMsg() != null && response.getMsg().indexOf("没有关注者") >= 0) {
								logger.warn("用户没有关注，执行重发！重发尝试次数："+ (i+1)+",open_id"+openId);
								if (i >= 5) {
									break;
								}
								else {
									if (i == 0) {
										
										sendSms(smsMsgContent);
										sendSmsFlag = false;
									}
								}
								Thread.sleep(resendTimeLong[i]*1000);//重发次数越大，间隔时间越长
								
//								addResendMessage(new WaitMessage(appId, privateKey, request, msgLog));
//								break;
							}
							else {
								sendSmsFlag = true;
								//不是用户没有关注引发的失败，不执行重发
								break;
							}

						}
					}
				
					
				} catch (Exception e) {
					sendSmsFlag = true;
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					
					logger.error("调用sendTemlateMessage方法，推送模版消息-支付宝异常"+",open_id"+openId,e);
					logger.error(ErrorCodeDefine.getStackTrace(e)+",open_id"+openId);
				}
				finally {
					saveMsgLog(msgLog);
					if (sendSmsFlag) {
						sendSms(smsMsgContent);
 					}
				}
			}
		});
		
		
	}
	/**
	 * 参数非空验证
	 * @param param
	 * @param fieldNames
	 */
	private static void validParam(JSONObject param,String fieldNames) {
		if ( ! StringUtils.isBlank(fieldNames)) {
			String[] arrFieldName = fieldNames.split(",");
			for (String fieldName : arrFieldName) {
				if (StringUtils.isBlank(param.getString(fieldName.trim()))) {
					throw new CallException(ErrorCodeDefine.MESSAGE_PARAM,"参数异常"+fieldName.trim());
				}
			}
		}
	}
	/**
	 * 推送挂号通知消息
	 * 挂号通知主要是用在（医院里的医生临时停诊或是用 户就诊前一日提醒用户的）
	 * @param openId
	 * @param hospitalCode
	 * @param regNotify RegNotify对象
	 */
	public static void sendRegNotify(final String strJsonRegNotify,final String appId,final String  privateKey) {
		try {
			logger.info("sendRegNotify:推送消息，收到请求->"+strJsonRegNotify);
			
			JSONObject param = JsonUtils.parseObject(strJsonRegNotify);
			
			if (param.get("hos_info") instanceof String) {
				param.put("hos_info", JsonUtils.parseObject(param.get("hos_info")));
			}
			if (param.get("dept_info") instanceof String) {
				param.put("dept_info", JsonUtils.parseObject(param.get("dept_info")));
			}
			if (param.get("doctor_info") instanceof String) {
				param.put("doctor_info", JsonUtils.parseObject(param.get("doctor_info")));
			}
			final RegNotify regNotify = JsonUtils.parseObject(param, RegNotify.class);
			logger.info("sendRegNotify:转换后的regNotify对象："+ JsonUtils.toJsonString(regNotify));
			
			
			//参数验证
			validParam(param,"org_app_code,user_id,operate,third_no,patient_name,hos_info,dept_info,doctor_info,treat_date,biz_type,order_link");
			validParam(JsonUtils.parseObject(regNotify.getHosInfo()),"code,name,phone");
			validParam(JsonUtils.parseObject(regNotify.getDeptInfo()),"code,name,location");
			validParam(JsonUtils.parseObject(regNotify.getDoctorInfo()),"code,name,sex");
			
			if (( ! StringUtils.isBlank(regNotify.getNotifyTime()) )&& ErrorCodeDefine.YYYYMMDDHHMMSS.parse(regNotify.getNotifyTime()).before(Calendar.getInstance().getTime())) {
				throw new CallException(ErrorCodeDefine.MESSAGE_PARAM, "通知时间必须大于当前日期");
			}
			
			if (ErrorCodeDefine.YYYYMMDDHHMMSS.parse(regNotify.getTreatDate()).before(Calendar.getInstance().getTime())) {
				throw new CallException(ErrorCodeDefine.MESSAGE_PARAM, "就诊时间必须大于当前日期");
			}
			/**
			 * 排队号,不传递，会导致参数无效错误
			 */
			if (StringUtils.isEmpty(regNotify.getLineNo())) {
				regNotify.setLineNo("10");
			}
			final String openId = regNotify.getUserId();
			final MsgLogExt msgLog = new MsgLogExt(regNotify.getUserId(),"",appId,"alipay","regNotify");
			
			logger.debug("sendRegNotify:"+ JsonUtils.toJsonString(msgLog));
			executors.execute(new Runnable() {
				public void run() {
					try {
						AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
						
						RegNotifyRequest request = new RegNotifyRequest();
						
						String requestStr = JsonUtils.toJsonString(regNotify);
						request.setBizContent(requestStr);
						logger.info("requestStr="+request.getBizContent());
						
						JSONObject jsonObject = new JSONObject();
					
						// 使用SDK，调用单发接口发送纯文本消息
						RegNotifyResponse response = alipayClient.execute(request);
						if (response != null && response.isSuccess() && "10000".equals(response.getCode())) {
							msgLog.setPushStatusSuccess();
							jsonObject.put("errcode", "0");
							jsonObject.put("errmsg", response.getMsg());
							logger.info("sendRegNotify:推送消息成功 " + response.getCode()+",open_id"+openId);
							if (logger.isDebugEnabled()) {
								logger.debug("sendRegNotify:推送消息成功 : response = " + response.getBody()+",open_id"+openId);
							}
							
						} else {
							msgLog.setPushStatusFail();

							msgLog.setErrorMsg(JsonUtils.toJsonString(response));
							logger.error("sendRegNotify:error, return:"+JSON.toJSONString(response)+",open_id"+openId);
							
						}
						
					} catch (Exception e) {
						msgLog.setPushStatusException();
						msgLog.setErrorMsg(e.toString());
						
						logger.error("sendRegNotify:推送消息-支付宝异常"+",open_id"+openId,e);
					}
					finally {
						saveMsgLog(msgLog);
					}
				}
			});
		} 
		catch (CallException ce) {
			logger.error("",ce);
			throw ce;
		}
		catch (Exception e) {
			logger.error("sendRegNotify消息发送异常",e);
			throw new CallException(ErrorCodeDefine.MESSAGE_COMMON, "消息发送异常",e);
		}
		
		
	}
	
	public static String convertMap2UrlEncodeString(Map<String, Object> data,String charset){
		TreeMap<String, Object> tree = new TreeMap<String, Object>();
		Iterator<Entry<String, Object>> it = data.entrySet().iterator();
		while (it.hasNext()) {
			Entry<String, Object> en = it.next();
			tree.put(en.getKey(), en.getValue());
		}
		
		it = tree.entrySet().iterator();
		StringBuffer sf = new StringBuffer();
		while (it.hasNext()) {
			Entry<String, Object> en = it.next();
			try {
				Object v = en.getValue();
				if (v == null) {
					
				}
				else {
					if (v instanceof Map) {
						sf.append(en.getKey()+"="+URLEncoder.encode(en.getValue().toString(),charset)+"&");
					}
					else {
						sf.append(en.getKey()+"="+URLEncoder.encode(en.getValue().toString(),charset)+"&");
					}
				}
				
				
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		String params=sf.toString();
		params = params.substring(0, params.length() - 1);
		return params;
	}
	/**
	 * 根据平台orgAppCode推送不同平台模版消息-支付宝
	 * 
	 * @param openId  接收人ID
	 * @param orgAppCode
	 * @param orgCode 可以空
	 * @param appId
	 * @param privateKey 
	 * @param msgTemplateContents 模板消息内容
	 * @param headColor  标题栏颜色
	 * @param url 点击后转向的URL
	 * @param templateId 模板ID
	 * @return
	 */
	public static void sendTemlateMessageByAppCode(final String openId, String orgAppCode, String orgCode,final String templateId,final List<MsgTemplateContent> msgTemplateContents,
			final String url, final String headColor,Short platformType,final String appId,final String privateKey,final String publicKey,final String smsMsgContent) {
		
		logger.info("推送模版消息，收到请求->openId="+openId+",orgAppCode="+orgAppCode+",orgCode="+orgCode+",templateId="+templateId+","+JSON.toJSONString(msgTemplateContents));
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！");
			return;
		}
		
		
//		ResCommon<PaymentSettingResponse> responsePayment= PayService.getPayClient().queryPaymentSettingByAppcodeAndOrgcodeAndPaymode(orgAppCode, orgCode, platformType);
//		if ( ! "0".equals(responsePayment.getResultCode())) {
//			logger.error("无法获得APPID信息");
//			throw new CallException(ErrorCodeDefine.MESSAGE_COMMON,"无法获得APPID信息");
//		}
//		logger.debug("获取的app信息："+JsonUtils.toJsonString(responsePayment));
//		PaymentSettingResponse paymentSettingResponse = responsePayment.getResult();
//		
//		final String privateKey = paymentSettingResponse.getPrivateKey();
//		final String appId = paymentSettingResponse.getPayAppId();
//		
//		//TODO:需要修改这个逻辑
//		final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALocAGAyUmjls8/f687w5kcFnVYxy2lze5jlR27uPAojmD2rpewErTo1wnGO31B+vZd+0eZypqPK3lKR1Yx/I+wpxIxBobgmw10p+KgofJ1TFq+YUby4XCsAa2pLKS37WbsoHjesyXgp8AA/4xhtN8aaXOAIO4l4ZiYIAzj40rWnAgMBAAECgYB/zPLFHElTF0nfGdmIhgzcAJMGubMBevgJCol/N8GrBL5quxB5fsymCHy6Fm5rjF0NR11Ebr7YA1ugP9zxWe2D9qR76753cQfawWS4F8ZudJ63JEgjApGPjykDzJEyp66/ydfAnwAMzrag2SHcCQbgr4tmgD2OAkafJeRqiSoQYQJBAOrd4WUhP1VN/CaPLWgvynsL24w+YPrb4g6QtBNaFQFpJDPsfMMiqZOudJGjBZPR5uX+GzAOVamOPPiSwDUTfusCQQDK2wDHAkkVioSpOFLLDFPQ+2cb5Le3pnQJLGcj9lQ+iKG8VkIfDOFjbYfcA9agf17ttWcaF96Y0qtCQB44Jo01AkEAhjFSKBsP+ah+KnXiBsZPlXBX99BoTsy1Y4cQLIJqwAyX78buHfw/Ea860T9o32Wt3LkMRa/bB+7KLWiDw4+pEwJAWwUVPjZaUJ4MlFk/XPg1C4oiY7Omc3LukccoqEw41K490+HoXUJMR264DRJz1SQRlhtVHbIkIPI2Ac3/QTabGQJAa0ENFsyIrrlZFQvm1VciERrOvcGUqMlKpcRCMWyIulwcP8DOfRH3HrN/XFYN9jt3zznhsLxL9EQr8NFWHnuFwQ==";
//		final String appId = "2015102000489434";
		
		
		final MsgLogExt msgLog = new MsgLogExt(openId,"",appId,"alipay",templateId);
		logger.debug("发送模板消息:"+ JsonUtils.toJsonString(msgLog));
		executors.execute(new Runnable() {
			public void run() {
				boolean sendSmsFlag = false;
				try {
					//延迟8秒发
					Thread.sleep(8000);
					AlipayClient alipayClient = null;
					if (publicKey.length() > 256) {
						alipayClient = AlipayAPIClientFactory.getAlipayClientRSA2(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET, publicKey);
					}else{
						alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					}
					AlipayMobilePublicMessageSingleSendRequest request = new AlipayMobilePublicMessageSingleSendRequest();
					String requestStr = "";
					try {
						requestStr = AlipayMessageBuildUtils.buildTemplateMsg(openId, templateId, msgTemplateContents, url, headColor);
						logger.info("requestStr:" + requestStr+",open_id"+openId);
						if (logger.isDebugEnabled()) {
							logger.debug("requestStr----" + requestStr+",open_id"+openId);
						}
						msgLog.setPushContent(requestStr);
					} catch (Exception e) {
						logger.error("格式解析异常");
						throw e;
					}
					request.setBizContent(requestStr);
					JSONObject jsonObject = new JSONObject();
					
					//如果用户没有关注导致的失败，执行重发。尝试6次重发
					for (int i = 0;i<6;i++) {
						
						// 使用SDK，调用单发接口发送纯文本消息
						AlipayMobilePublicMessageSingleSendResponse response = alipayClient.execute(request);
						if (response != null && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
							msgLog.setPushStatusSuccess();
							jsonObject.put("errcode", "0");
							jsonObject.put("errmsg", response.getMsg());
							logger.info("推送模版消息成功 " + response.getCode()+",open_id"+openId);
							if (logger.isDebugEnabled()) {
								logger.debug("推送模版消息成功 : response = " + response.getBody()+",open_id"+openId);
							}
							sendSmsFlag = false;
							//发送成功，不执行重发
							break;
							
						} else {
							
							msgLog.setPushStatusFail();

							msgLog.setErrorMsg(JsonUtils.toJsonString(response));
							logger.error("alipayClient.execute(request) return:"+JSON.toJSONString(response)+",open_id"+openId);
							
							//用户没有关注，执行重发。尝试6次重发
							if (response.getMsg() != null && response.getMsg().indexOf("没有关注者") >= 0) {
								sendSmsFlag = false;
								logger.warn("用户没有关注，执行重发！重发尝试次数："+ (i+1)+",open_id"+openId);
								if (i >= 5) {
									break;
								}
								else {
									if (i == 0) {
										sendSmsFlag = false;
										sendSms(smsMsgContent);
									}
								}
								Thread.sleep(resendTimeLong[i]*1000);//重发次数越大，间隔时间越长
								
//								addResendMessage(new WaitMessage(appId, privateKey, request, msgLog));
//								break;
							}
							else {
								sendSmsFlag = true;
								//不是用户没有关注引发的失败，不执行重发
								break;
							}

						}
					}
				
					
				} catch (Exception e) {
					sendSmsFlag = true;
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					
					logger.error("调用sendTemlateMessage方法，推送模版消息-支付宝异常"+",open_id"+openId);
					logger.error(ErrorCodeDefine.getStackTrace(e)+",open_id"+openId);
				}
				finally {
					saveMsgLog(msgLog);
					if (sendSmsFlag) {
						sendSms(smsMsgContent);
 					}
				}
			}
		});
		
		
	}
	
	public static void sendSms(String smsMsgContent) {
		if (StringUtils.isNotBlank(smsMsgContent)) {
			try {
				JSONObject param = JsonUtils.parseObject(smsMsgContent);
				String mobile = param.getString("sms_mobile");
				if (StringUtils.isNotBlank(mobile)) {
					MessageService.sendSms(smsMsgContent);
				}
				
			}
			catch (Exception ex) {
				logger.error("发送短信错误:"+smsMsgContent,ex);
			}
		}
	}
	
	
	/**
	 * 推送模版消息-支付宝
	 * 
	 * @param openId  接收人ID
	 * @param platform_org_app_code
	 * @param dev_org_code
	 * @param msgTemplateContents 模板消息内容
	 * @param headColor  标题栏颜色
	 * @param url 点击后转向的URL
	 * @param templateId 模板ID
	 * @return
	 */
	public static void sendTemlateMessageNew(final String openId, String orgAppCode, String orgCode,final String templateId,final List<MsgTemplateContent> msgTemplateContents,
			final String url, final String headColor,final JSONObject param,final String smsMsgContent) {
		
		logger.info("推送模版消息，收到请求->"+openId+","+orgCode+","+templateId+","+JSON.toJSONString(msgTemplateContents));
		if (StringUtils.isBlank(openId)) {
			logger.error("发送人为空！"+",open_id"+openId);
			return;
		}
		
		final String resendRuleId = param.containsKey("resend_rule_id") ? param.getString("resend_rule_id") : "";
		final int firstDelay = param.containsKey("first_delay") ? param.getIntValue("first_delay") : 0;
		
//		logger.debug("获取App信息:hospitalCode="+hospitalCode);
//		ResCommon<PaymentSettingResponse> responsePayment= PayService.getPayClient().queryPaymentSettingByAppcodeAndOrgcodeAndPaymode(orgAppCode, orgCode, platformType);
//		if ( ! "0".equals(responsePayment.getResultCode())) {
//			logger.error("无法获得APPID信息");
//			throw new CallException(ErrorCodeDefine.MESSAGE_COMMON,"无法获得APPID信息");
//		}
//		logger.debug("获取的app信息："+JsonUtils.toJsonString(responsePayment));
//		PaymentSettingResponse paymentSettingResponse = responsePayment.getResult();
//		
//		final String privateKey = paymentSettingResponse.getPrivateKey();
//		final String appId = paymentSettingResponse.getPayAppId();
		
		//TODO:需要修改这个逻辑
		final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALocAGAyUmjls8/f687w5kcFnVYxy2lze5jlR27uPAojmD2rpewErTo1wnGO31B+vZd+0eZypqPK3lKR1Yx/I+wpxIxBobgmw10p+KgofJ1TFq+YUby4XCsAa2pLKS37WbsoHjesyXgp8AA/4xhtN8aaXOAIO4l4ZiYIAzj40rWnAgMBAAECgYB/zPLFHElTF0nfGdmIhgzcAJMGubMBevgJCol/N8GrBL5quxB5fsymCHy6Fm5rjF0NR11Ebr7YA1ugP9zxWe2D9qR76753cQfawWS4F8ZudJ63JEgjApGPjykDzJEyp66/ydfAnwAMzrag2SHcCQbgr4tmgD2OAkafJeRqiSoQYQJBAOrd4WUhP1VN/CaPLWgvynsL24w+YPrb4g6QtBNaFQFpJDPsfMMiqZOudJGjBZPR5uX+GzAOVamOPPiSwDUTfusCQQDK2wDHAkkVioSpOFLLDFPQ+2cb5Le3pnQJLGcj9lQ+iKG8VkIfDOFjbYfcA9agf17ttWcaF96Y0qtCQB44Jo01AkEAhjFSKBsP+ah+KnXiBsZPlXBX99BoTsy1Y4cQLIJqwAyX78buHfw/Ea860T9o32Wt3LkMRa/bB+7KLWiDw4+pEwJAWwUVPjZaUJ4MlFk/XPg1C4oiY7Omc3LukccoqEw41K490+HoXUJMR264DRJz1SQRlhtVHbIkIPI2Ac3/QTabGQJAa0ENFsyIrrlZFQvm1VciERrOvcGUqMlKpcRCMWyIulwcP8DOfRH3HrN/XFYN9jt3zznhsLxL9EQr8NFWHnuFwQ==";
		final String appId = "2015102000489434";
		
		final MsgLogExt msgLog = new MsgLogExt(openId,"",appId,"alipay",templateId);
		logger.debug("发送模板消息:"+ JsonUtils.toJsonString(msgLog));
		executors.execute(new Runnable() {
			boolean sendSuccessFlag = false;
			public void run() {
				boolean bSaveLog = true;
				try {
					//首次发送延迟，单位秒
					if (firstDelay > 0) {
						Thread.sleep(firstDelay*1000);
					}
					sendingTemplateCount++;
					//延迟8秒发
//					Thread.sleep(8000);
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageSingleSendRequest request = new AlipayMobilePublicMessageSingleSendRequest();
					String requestStr = "";
					try {
						requestStr = AlipayMessageBuildUtils.buildTemplateMsg(openId, templateId, msgTemplateContents, url, headColor);
						logger.info("requestStr:" + requestStr+",open_id"+openId);
						if (logger.isDebugEnabled()) {
							logger.debug("requestStr----" + requestStr+",open_id"+openId);
						}
						msgLog.setPushContent(requestStr);
					} catch (Exception e) {
						logger.error("格式解析异常"+",open_id"+openId);
						throw e;
					}
					request.setBizContent(requestStr);
					JSONObject jsonObject = new JSONObject();
					
					// 使用SDK，调用单发接口发送纯文本消息
					AlipayMobilePublicMessageSingleSendResponse response = alipayClient.execute(request);
					
					//发送成功
					if (response != null && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
						msgLog.setPushStatusSuccess();
						jsonObject.put("errcode", "0");
						jsonObject.put("errmsg", response.getMsg());
						logger.info("推送模版消息成功 " + response.getCode()+",open_id"+openId);
						if (logger.isDebugEnabled()) {
							logger.debug("推送模版消息成功 : response = " + response.getBody()+",open_id"+openId);
						}
						sendSuccessFlag = true;
						
					} else {
						msgLog.setPushStatusFail();

						msgLog.setErrorMsg(JsonUtils.toJsonString(response));
						logger.info("alipayClient.execute(request) return:"+JSON.toJSONString(response)+",open_id"+openId);
						
						//判断是否重发
						if ( ! StringUtils.isBlank(resendRuleId)) {
							//获取重发规则
							ResendRuleVo resendRuleVo = JsonUtils.parseObject(param.getJSONObject("resend_rule"),ResendRuleVo.class);
							logger.debug("resendRuleVo="+ JsonUtils.toJsonString(resendRuleVo)+",open_id"+openId);
							if (resendRuleVo != null) {
								bSaveLog = false;
								addResendMessage(new ResendMessage(appId, privateKey, request, msgLog,resendRuleVo));
								
							}
							else {
								logger.error("指定的消息重发规则异常，resendRuleId="+resendRuleId+"，不再执行消息重发"+",open_id"+openId);
							}
						}
						
					}
					
				
					
				} catch (Exception e) {
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					logger.error("调用sendTemlateMessage方法，推送模版消息-支付宝异常"+",open_id"+openId);
					logger.error(ErrorCodeDefine.getStackTrace(e)+",open_id"+openId);
				}
				finally {
					sendingTemplateCount--;
					if (bSaveLog) {
						saveMsgLog(msgLog);
					}
					
					if ( ! sendSuccessFlag) {
						sendSms(smsMsgContent);
 					}
					
				}
			}
		});
		
		
	}
	
	
	/**
	 * 群发文本消息
	 * @param appId
	 * @param privateKey
	 * @param text
	 */
    public static void sendGroupTextMessage(final String hospitalCode,final String text) {
    	HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
		final String privateKey = appVo.getPrivateKey();
		final String appId = appVo.getAppId();
		final MsgLogExt msgLog = new MsgLogExt("",appVo.getHospitalId(),appId,"alipay","");
		msgLog.setPushContent(text);
		logger.debug("群发纯文本消息:"+ JsonUtils.toJsonString(msgLog));
    	executors.execute(new Runnable() {
			public void run() {
		        try {
		        	AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);

			        // 使用SDK，构建群发请求模型
			        AlipayOpenPublicMessageTotalSendRequest request = new AlipayOpenPublicMessageTotalSendRequest();
			        request.setBizContent(AlipayMessageBuildUtils.buildTextMsg(null, text));
			        
		            // 使用SDK，调用群发接口发送纯文本消息
		        	AlipayOpenPublicMessageTotalSendResponse response = alipayClient.execute(request);

		            //这里只是简单的打印，请开发者根据实际情况自行进行处理
		            if (null != response && response.isSuccess()) {
		                logger.debug("消息群发成功 : response = " + response.getBody());
		                msgLog.setPushStatusSuccess();
		            } else {
		                logger.warn("消息群发失败 code=" + response.getCode() + "msg=" + response.getMsg());
		                msgLog.setPushStatusFail();
		                msgLog.setErrorMsg(response.getMsg());
		            }
		        } catch (Exception e) {
		        	msgLog.setPushStatusException();
		        	msgLog.setErrorMsg(e.toString());
		            logger.error("消息群发失败:"+e.toString());
		        }
		        finally {
					saveMsgLog(msgLog);
				}
			}
		});
    	
    	
    }
    
    /**
     * 群发图文消息
     * @param appId
     * @param privateKey
     * @param imageMessage
     */
    public static void sendGroupImageMessage(final String hospitalCode,final ImageMessage imageMessage) {
    	HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
		final String privateKey = appVo.getPrivateKey();
		final String appId = appVo.getAppId();
		final MsgLogExt msgLog = new MsgLogExt("",appVo.getHospitalId(),appId,"alipay","");
		logger.debug("群发图文消息:"+ JsonUtils.toJsonString(msgLog));
    	executors.execute(new Runnable() {
			public void run() {

		        try {
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);

			        // 使用SDK，构建群发请求模型
			        AlipayOpenPublicMessageTotalSendRequest request = new AlipayOpenPublicMessageTotalSendRequest();
			        request.setBizContent(AlipayMessageBuildUtils.buildImageTextMsg(null, imageMessage.getDesc(), imageMessage.getImageUrl(), imageMessage.getTitle(), imageMessage.getUrl()));

		            // 使用SDK，调用群发接口发送图文消息
		        	AlipayOpenPublicMessageTotalSendResponse response = alipayClient.execute(request);

		            //这里只是简单的打印，请开发者根据实际情况自行进行处理
		            if (null != response && response.isSuccess()) {
		            	logger.debug("消息发送成功 : response = " + response.getBody());
		            	msgLog.setPushStatusSuccess();
		            } else {
		            	logger.warn("消息发送失败 code=" + response.getCode() + "msg=" + response.getMsg());
		            	msgLog.setPushStatusFail();
		            	msgLog.setErrorMsg(response.getMsg());
		            }
		        } catch (Exception e) {
		        	msgLog.setPushStatusException();
		        	msgLog.setErrorMsg(e.toString());
		            logger.error("消息发送失败"+e.toString());
		        }
		        finally {
					saveMsgLog(msgLog);
				}
			}
		});
    	

    }
    /**
	 * 支付宝匹配推送 精准推送
	 * 
	 * @param appId
	 * @param hospitalCode
	 * @param mobile 手机号码
	 * @param templateId 支付宝模板ID
	 * @return
	 */
	public static void sendAlipayMessageTemplateByMoble(String hospitalCode, final String mobile,final String templateId) {
		HospitalCodeAndAppVo appVo = getHospitalInfo(hospitalCode);
		final String privateKey = appVo.getPrivateKey();
		final String appId = appVo.getAppId();
		final MsgLogExt msgLog = new MsgLogExt(mobile,appVo.getHospitalId(),appId,"alipay",templateId);
		logger.debug("发送精准推送/匹配推送消息:"+ JsonUtils.toJsonString(msgLog));
    	executors.execute(new Runnable() {
			public void run() {
				try {
					AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(appId, privateKey, "json", AlipayConstant.ALIPAY_CHAR_SET);
					AlipayMobilePublicMessageMatcherSendRequest request = new AlipayMobilePublicMessageMatcherSendRequest();
					String requestStr = AlipayMessageBuildUtils.buildTemplateMsg(mobile, templateId);
//					requestStr = AlipayMessageBuildUtils.buildTemplateMsg(openId, templateId, msgTemplateContents, url, headColor);
					logger.info("匹配推送: biz_content requestStr:" + requestStr);
					msgLog.setPushContent(requestStr);
					request.setBizContent(requestStr);
					JSONObject jsonObject = new JSONObject();
					
					// 使用SDK，调用单发接口发送纯文本消息
					AlipayMobilePublicMessageMatcherSendResponse response = alipayClient.execute(request);
					if (response == null) {
						// http请求失败
						logger.error("请求支付宝匹配推送失败 response is null");
						msgLog.setPushStatusFail();
						msgLog.setErrorMsg("请求支付宝匹配推送失败 response is null");
					} else {
						logger.info("匹配推送消息返回 response: " + JSON.toJSONString(response));
						// code = 12036表示模版校验中，也算推送成功
						String code = response.getCode();
						String errcode = "1";
						String errmsg = response.getMsg();
						msgLog.setPushStatusFail();
						if (response.isSuccess() && (AlipayConstant.ALIPAY_SUCCESS_STR.equals(code) || "12036".equals(code))) {
							errcode = "0";
							msgLog.setPushStatusSuccess();
						}
						else {
							msgLog.setErrorMsg(JsonUtils.toJsonString(response));
						}
						jsonObject.put("errcode", errcode);
						jsonObject.put("errmsg", errmsg);
						logger.info("匹配推送消息返回 jsonObject: " + JSON.toJSONString(jsonObject));
					}
				} catch (Exception e) {
					msgLog.setPushStatusException();
					msgLog.setErrorMsg(e.toString());
					logger.error("调用sendAlipayMessageTemplateByMoble精准推送，匹配推送消息-支付宝异常");
					e.printStackTrace();
				}
				finally {
					saveMsgLog(msgLog);
				}
			}
		});
	}

	/**
	 * 保存发送日志
	 * @param msgLog
	 */
	public static void saveMsgLog(MsgLog msgLog) {
		try {
			//处理发送日志
			MsgLogDao msgLogDao = SpringContextHolder.getBean(MsgLogDao.class);
			if (StringUtils.isBlank(msgLog.getId())) {
				msgLog.setId(IDUtils.getUUID32());
			}

			msgLogDao.insert(msgLog);
		}
		catch (Exception ex) {
			logger.error(ex.toString());
		}
	}
	
	public static void main(String[] args){
//		java.util.Random r = new Random();
//		try {
//			for (int i = 0;i<10;i++) {
//				addResendMessage(new WaitMessage(""+i, "secret"+i, null, new MsgLogExt()));
//				Thread.sleep(r.nextInt(300));
//			}
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		
//		AlipayMessageSendUtils util=new AlipayMessageSendUtils();
//		List<MsgTemplateContent> lists=new ArrayList<MsgTemplateContent>();
//		
//		MsgTemplateContent c1=new MsgTemplateContent();
//		c1.setNode("remark");
//		c1.setValue("取药地址:请到西药房1号窗口取药");
//		c1.setFontColor("#00ff22");
//		
//		MsgTemplateContent c2=new MsgTemplateContent();
//		c1.setNode("first");
//		c1.setValue("你完成了一笔门诊缴费。");
//		c1.setFontColor("#00ff22");
//		
//		MsgTemplateContent c3=new MsgTemplateContent();
//		c1.setNode("keyword1");
//		c1.setValue("胡文杰");
//		c1.setFontColor("#00ff22");
//		
//		MsgTemplateContent c4=new MsgTemplateContent();
//		c1.setNode("keyword2");
//		c1.setValue("YCP201611072208044453");
//		c1.setFontColor("#00ff22");
//		
//		lists.add(c1);
//		lists.add(c2);
//		lists.add(c3);
//		lists.add(c4);
//		
//		util.sendTemlateMessage("2088412374886663",  "0b0ed0499a8911e6951000163e00175d","eb30ad9c30ec4f5cb8200a434658604e", lists,"", "red");
	}
	
	
	
	
	
	
	
	
	
	
	
	
	

	
	
	
	
	
	
	
	
	/**
	 * 正在发送的消息个数
	 */
	private static int sendingTemplateCount = 0;
	
	/**
	 * 正在重新发送的消息个数
	 */
	private static int resendingTemplateCount = 0;

	
	/**
	 * 要发送的消息队列
	 */
	public static ConcurrentLinkedQueue<String> messageQueue = new ConcurrentLinkedQueue<String>();
	/**
	 * 允许的同时进行的消息发送个数，即并发消息发送个数最大值
	 */
	private static final int MAX_SENDING_COUNT = 100;
	
	/**
	 * 是否进行消息发送
	 */
	private static boolean bSendMessageFlag = true;
	
	/**
	 * 防止重复运行
	 */
	private static boolean bSendMessagRunningFlag = false;
	

	

	private static boolean resendMessage(ResendMessage resendMessage) {
		
		logger.info("推送模版消息，收到请求->"+ JsonUtils.toJsonString(resendMessage));
		
		boolean bSuccess = false;
		MsgLogExt msgLog = resendMessage.getMsgLog();
		try {
			resendingTemplateCount++;
			//延迟8秒发
//			Thread.sleep(8000);
			AlipayClient alipayClient = AlipayAPIClientFactory.getAlipayClient(resendMessage.getAppId(), resendMessage.getPrivateKey(), "json", AlipayConstant.ALIPAY_CHAR_SET);
			//如果用户没有关注导致的失败，执行重发。尝试6次重发

			// 使用SDK，调用单发接口发送纯文本消息
			AlipayMobilePublicMessageSingleSendResponse response = alipayClient.execute(resendMessage.getRequest());
			if (response != null && response.isSuccess() && AlipayConstant.ALIPAY_SUCCESS_STR.equals(response.getCode())) {
				bSuccess = true;
				msgLog.setPushStatusSuccess();
				logger.info("推送模版消息成功 " + response.getCode());
				if (logger.isDebugEnabled()) {
					logger.debug("推送模版消息成功 : response = " + response.getBody());
				}
				
			} else {
				msgLog.setPushStatusFail();

				msgLog.setErrorMsg(JsonUtils.toJsonString(response));
				logger.info("重发消息失败：return:"+JSON.toJSONString(response));


			}
		} catch (Exception e) {
			msgLog.setPushStatusException();
			msgLog.setErrorMsg(e.toString());
			logger.error("重发消息异常，推送模版消息-支付宝异常");
			logger.error(ErrorCodeDefine.getStackTrace(e)+ JsonUtils.toJsonString(resendMessage));
		}
		finally {
			resendingTemplateCount--;
		}

		return bSuccess;
	}
	

	
	private static void addResendMessage(ResendMessage resendMessage) {
		ResendMessageThread.addMessage(resendMessage);
	}
	

	
	private static class ResendMessage  {
		private String appId;
		private String privateKey;
		private AlipayMobilePublicMessageSingleSendRequest request;
		private MsgLogExt msgLog;
		private int timeIndex = 0;
		private boolean needSend = true;
		ResendRuleVo resendRuleVo;
		private Long startTime = System.currentTimeMillis();
		public ResendMessage(String appId, String privateKey, AlipayMobilePublicMessageSingleSendRequest request, MsgLogExt msgLog, ResendRuleVo resendRuleVo) {
			this.appId = appId;
			this.privateKey = privateKey;
			this.request = request;
			this.msgLog = msgLog;
			this.resendRuleVo = resendRuleVo;
		}	
		
		
		
		public AlipayMobilePublicMessageSingleSendRequest getRequest() {
			return request;
		}
		public void setRequest(AlipayMobilePublicMessageSingleSendRequest request) {
			this.request = request;
		}
		public MsgLogExt getMsgLog() {
			return msgLog;
		}
		public void setMsgLog(MsgLogExt msgLog) {
			this.msgLog = msgLog;
		}
		public int getTimeIndex() {
			return timeIndex;
		}
		public void setTimeIndex(int timeIndex) {
			this.timeIndex = timeIndex;
		}
		public Long getStartTime() {
			return startTime;
		}
		public void setStartTime(Long startTime) {
			this.startTime = startTime;
		}
		public String getAppId() {
			return appId;
		}
		public void setAppId(String appId) {
			this.appId = appId;
		}
		public String getPrivateKey() {
			return privateKey;
		}
		public void setPrivateKey(String privateKey) {
			this.privateKey = privateKey;
		}

		public boolean isNeedSend() {
			return needSend;
		}

		public void setNeedSend(boolean needSend) {
			this.needSend = needSend;
		}



		public ResendRuleVo getResendRuleVo() {
			return resendRuleVo;
		}



		public void setResendRuleVo(ResendRuleVo resendRuleVo) {
			this.resendRuleVo = resendRuleVo;
		}
		
		
	}
	
	/**
	 * 重发消息线程
	 * @author adriftor
	 *
	 */
	private static class ResendMessageThread implements Runnable {
		
		private static List<ResendMessage> listMessage = new LinkedList<ResendMessage>();
		private static boolean isRunning = false;
		private static boolean runFlag = true;
		@Override
		public void run() {
			
			if (isRunning) {
				logger.warn("消息重发处理线程已经启动,请勿重复运行");
				return;
			}
			while (runFlag) {
				isRunning = true;
				try {
					int size = listMessage.size();
					if (size == 0) {
						if (System.currentTimeMillis()%20 == 0) {
							logger.debug("消息重发：没有需要重发的消息");
						}
						
						Thread.sleep(3000);
					}
					for (int i = 0;i<listMessage.size();i++) {
						
						ResendMessage resendMessage = listMessage.get(i);
						ResendRuleVo resendRuleVo = resendMessage.getResendRuleVo();
							
						//判断重发次数，是否需要重发，是否有重发规则
						if ( ! resendMessage.isNeedSend() || resendRuleVo == null || resendMessage.getTimeIndex() >= resendRuleVo.getResendCount()) {
							logger.debug("消息重发：不需要发送或已经超过重发次数："+ JsonUtils.toJsonString(resendMessage));
							listMessage.remove(i);
							i--;
							saveMsgLog(resendMessage.getMsgLog());
							continue;
						}
	
						
						Long curTime = System.currentTimeMillis();
						
						int[] resendTimeLong = null;
						if ( ! StringUtils.isBlank(resendRuleVo.getResendSeq())) {
							
							//解析重发间隔
							String[] resendSeqArr = resendRuleVo.getResendSeq().split(",");
							resendTimeLong = new int[resendSeqArr.length];
							for (int m = 0;m < resendSeqArr.length;m++) {
								resendTimeLong[m] = Integer.parseInt(resendSeqArr[m]);
							}
							
							
							if (resendMessage.getTimeIndex() >= resendTimeLong.length) {
								logger.error("重发次数大于规则设置的时间间隔个数");
								resendMessage.setNeedSend(false);
							}
							else {
								if (curTime - resendMessage.getStartTime() > resendTimeLong[resendMessage.getTimeIndex()]*1000) {
									
									logger.debug("消息重发：已经达到重发时间："+ JsonUtils.toJsonString(resendMessage));
									resendMessage.setStartTime(curTime);
									resendMessage.setTimeIndex(resendMessage.getTimeIndex()+1);
									
									//执行发送消息
									boolean bResult = resendMessage(resendMessage);
									if (bResult) {
										logger.debug("消息重发成功（"+resendMessage.getAppId()+"）："+ JsonUtils.toJsonString(resendMessage));
										resendMessage.setNeedSend(false);
									}
									else {
										logger.debug("消息重发失败（"+resendMessage.getAppId()+"）："+ JsonUtils.toJsonString(resendMessage));
									}
								}
								else {
//									logger.debug("尚未达到重发时间："+resendMessage.getAppId()+"("+(curTime - resendMessage.getStartTime() - resendTimeLong[resendMessage.getTimeIndex()]*100)+")");
								}
							}
							
						}
						else {//没有定义消息重发间隔，也按不重发处理
							resendMessage.setNeedSend(false);
						}
						
						
							
					}
					
					
				}
				catch (Exception ex) {
					logger.error("重发消息调度运行失败："+ ErrorCodeDefine.getStackTrace(ex));
				}
				finally {
					try {
						Thread.sleep(100);
					}
					catch (Exception ex) {
						
					}
				}
			}
			
		}
		
		/**
		 * 停止消息重发处理线程
		 */
		public static void stop() {
			logger.info("停止消息重发线程");
			runFlag = false;
			isRunning = false;
		}
		public static void addMessage(ResendMessage resendMessage) {
			listMessage.add(resendMessage);
		}
		
		public static int getCacheCount() {
			return listMessage.size();
		}
	}

	/**
	 * 停止消息重发处理线程
	 */
	public static void stopReSend() {
		ResendMessageThread.stop();
	}
	
	/**
	 * 停止消息重发送线程
	 */
	public static void stopSend() {
		logger.info("停止消息发送线程");
		bSendMessageFlag = false;
	}
	
	/**
	 * 正在发送的消息个数
	 * @return
	 */
	public static int getSendingTemplateCount() {
		return sendingTemplateCount;
	}

	/**
	 * 正在重发的消息个数
	 * @return
	 */
	public static int getResendingTemplateCount() {
		return resendingTemplateCount;
	}
	
	/**
	 * 要执行重发的消息个数
	 * @return
	 */
	public static int getResendTemplateCacheCount() {
		return ResendMessageThread.getCacheCount();
	}

	/**
	 * 推送模版消息
	 * yyt.alipay.alipaymessage.template.send
	 * @param toUser  接收人ID
	 * @param hospitalCode 
	 * @param headColor  标题栏颜色
	 * @param url 点击后转向的URL
	 * @param templateId 模板ID 
	 * @param list_msg_template_content List<MsgTemplateContent>数组对象，[{value:"显示的文本信息",node:"变量名",font_color:"字体颜色"}]
	 * @return
	 */
	public void sendAlipayMessageTemplate(String strJson,String sessionId) {
		//直接把要发送的模板消息放入队列里

	}
	
	private static class SendMessageThread implements Runnable {
		/**
		 * 消息发送
		 */
		public void run() {
			
			if (bSendMessagRunningFlag) {
				logger.error("消息发送已经运行，请勿重复运行");
				return;
			}
			
			bSendMessagRunningFlag = true;
			
			int runCount = 0;
			while (bSendMessageFlag) {
				Long start = System.currentTimeMillis();
				int maxCount = 0;
				try {
					maxCount = 0;
					runCount++;
					if (System.currentTimeMillis() % 20 == 0) {
						logger.debug("消息发送运行开始,runCount="+runCount);
					}
					
					
					//判断最大可以取多少条消息进行发送
					maxCount = MAX_SENDING_COUNT - sendingTemplateCount - resendingTemplateCount;
					if (System.currentTimeMillis() % 20 == 0) {
						logger.debug("允许进行发送的消息最大数量："+maxCount);
					} 
					if (maxCount > 0) {//如果允许发送，则拿出消息进行发送
						
						for (int i = 0;i<maxCount;i++) {
							
							String strJson = getMessageFromMq();//取消息
							if ( ! StringUtils.isEmpty(strJson)) {
								
								JSONObject param = JsonUtils.parseObject(strJson);
								
								if (param.containsKey("list_msg_template_content")) {//模板消息
									
									List<MsgTemplateContent> listMsgTemplateContent = JsonUtils.parseArray(JsonUtils.toJsonString(param.getJSONArray("list_msg_template_content")),MsgTemplateContent.class);
									
									sendTemlateMessageNew(param.getString("to_user"),param.getString("org_app_code"), param.getString("org_code"),
											param.getString("template_id"), 
											listMsgTemplateContent, 
											param.getString("url"), 
											param.getString("head_color"),
											param, JsonUtils.toJsonString(param.get("sms_msg_content")));
								}
								else if (param.containsKey("text")) {//文本消息
									sendTextMessage(param.getString("to_user"),param.getString("org_app_code"), param.getString("text"),param.getShortValue("platform_type"),param.getString("app_id"),param.getString("app_secret"), JsonUtils.toJsonString(param.get("sms_msg_content")));
								}
								
							}
							else {
								break;
							}
							
						}
						
					}
					else {
						logger.warn("消息服务器负荷已经达到设定的上限");
					}
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("sendMessageFromMq运行发生错误");
					logger.error(ErrorCodeDefine.getStackTrace(e));
				}
				finally {
					if (maxCount != MAX_SENDING_COUNT) {
						logger.debug("消息发送运行完成,runCount="+runCount+",运行时间："+(System.currentTimeMillis() - start)+"毫秒");
					}
					try {
						Thread.sleep(3000);
					}
					catch (Exception ex) {
						
					}
				}
				
			}
			
			
		}
	}
	

	
	
	
	/**
	 * 从消息队里里获取一个消息
	 * @return 如果没有消息，返回null
	 */
	public static String getMessageFromMq() {
		return messageQueue.poll();
		
	}
	
	/**
	 * 将消息加入到发送队列 
	 * @param strJson 消息
	 */
	public static void addMessageToMq(String strJson) {
		
		if ( ! StringUtils.isBlank(strJson)) {
			messageQueue.offer(strJson);
			//缓存
//			CacheService.setGlobalKey(system, region, key, jsonData, expireTime)；
			//mq队列
		}
		else {
			throw new CallException(ErrorCodeDefine.MESSAGE_VALUE, "消息不允许为空");
		}
		
	}
	
	
	/**
	 * 启动发送和重发线程
	 */
	static {
//		new Thread(new SendMessageThread()).start();
//		new Thread(new ResendMessageThread()).start();
	}

}
